import editorStyle from "../util/defaultStyle";

export default function (G6, payload) {

    let behavior = {
        getDefaultCfg() {
            return {
                updateEdge: true,
                delegate: true,
                delegateStyle: {},
                dragEdge: false,
            };
        },
        getEvents() {
            return {
                'anchor:dragstart': 'onDragStart',
                'anchor:drag': 'onDrag',
                'anchor:dragend': 'onDragEnd',
                'anchor:dragenter': 'onDragEnter',
                'anchor:dragleave': 'onDragLeave',
            };
        },
        onDragEnter(e) {
            if (!this.origin) {
                return;
            }
            if (!this.sameNode(e)) {
                e.item.setHotspotActived(true);
                this.origin.targetNode = e.target.getParent().getParent().get('item');
                this.origin.targetAnchor = e.item.get('index');
            }
        },
        onDragLeave(e) {
            if (!this.origin) {
                return;
            }
            if (!this.sameNode(e)) {
                e.item.setHotspotActived(false);
                this.origin.targetNode = null;
                this.origin.targetAnchor = null;
            }
        },
        onDragStart(e) {
            const node = e.target.getParent().getParent().get('item');
            const anchorIndex = e.item.get('index');
            const point = node.getAnchorPoints()[anchorIndex];
            this.target = e.item;
            const groupId = node.get('groupId');
            if (groupId) {
                const subProcessNode = e.target.getParent().getParent().getParent().getParent().get('item');
                const subProcessBBox = subProcessNode.getBBox();
                this.origin = {
                    x: point.x + subProcessBBox.x + subProcessBBox.width / 2,
                    y: point.y + subProcessBBox.y + subProcessBBox.height / 2,
                    sourceNode: node,
                    sourceAnchor: anchorIndex,
                };
                this.dragEdgeBeforeShowAnchorBySub(subProcessNode);
            } else {
                this.origin = {
                    x: point.x,
                    y: point.y,
                    sourceNode: node,
                    sourceAnchor: anchorIndex,
                };
                this.dragEdgeBeforeShowAnchor(e);
            }
            this.graph.set('edgeDragging', true);
        },
        onDrag(e) {
            if (!this.origin) {
                return;
            }
            this._updateEdge(this.target, e);
        },
        onDragEnd(e) {
            const delegateShape = e.item.get('edgeDelegate');
            if (delegateShape) {
                delegateShape.remove();
                this.target.set('edgeDelegate', null);
            }
            this._updateEdge(this.target, e, true);
            if (!this.origin) {
                return;
            }
            this.graph.setItemState(this.origin.sourceNode, 'show-anchor', false);
            this.target = null;
            this.origin = null;
            this.graph.set('edgeDragging', false);
        },
        sameNode(e) {
            return e.target.cfg.type === 'marker' && e.target.getParent() && e.target.getParent().getParent().get('item').get('id') === this.origin.sourceNode.get('id')
        },
        dragEdgeBeforeShowAnchorBySub(subProcessNode) {
            const group = subProcessNode.getContainer();
            group.nodes.forEach(a => {
                const aGroup = a.getContainer();
                aGroup.showAnchor();
                aGroup.anchorShapes.forEach(b => b.get('item').showHotpot());
            });
        },
        dragEdgeBeforeShowAnchor(e) {
            const sourceGroupId = this.origin.sourceNode.getModel().groupId;
            this.graph.getNodes().forEach(node => {
                if (node.getModel().clazz === 'start'
                    || node.getModel().clazz === 'timerStart'
                    || node.getModel().clazz === 'messageStart')
                    return;
                const targetGroupId = node.getModel().groupId;
                if (!sourceGroupId && targetGroupId || sourceGroupId && !targetGroupId || sourceGroupId !== targetGroupId)
                    return;
                const group = node.getContainer();
                group.showAnchor();
                group.anchorShapes.forEach(a => a.get('item').showHotpot())
            });
        },
        _updateEdge(item, e, force) {
            const x = e.x;
            const y = e.y;
            if (this.delegate && !force) {
                this._updateEdgeDelegate(item, x, y);
                return;
            }
            const node = e.target.getParent().getParent().get('item');
            const groupId = node.get('groupId');
            if (groupId) {
                this._addSubProcessEdge(node, e);
            } else {
                this.addEdge(e);
            }
            this._clearAllAnchor();
            this.graph.paint();
        },
        _updateEdgeDelegate(item, x, y) {
            const self = this;
            let edgeShape = item.get('edgeDelegate');
            if (!edgeShape) {
                const parent = self.graph.get('group');
                edgeShape = parent.addShape('line', {
                    attrs: {
                        x1: this.origin.x,
                        y1: this.origin.y,
                        x2: x,
                        y2: y,
                        ...editorStyle.edgeDelegationStyle,
                    }
                });
                edgeShape.set('capture', false);
                item.set('edgeDelegate', edgeShape);
            }
            edgeShape.attr({x2: x, y2: y});
            this.graph.paint();
        },
        _clearAllAnchor() {
            this.graph.getNodes().forEach(node => {
                const group = node.getContainer();
                group.clearAnchor();
            });
        },
        _addSubProcessEdge(node, e) {
            if (this.origin.targetNode) {
                const group = node.getContainer().getParent().getParent();
                const subProcess = node.getContainer().getParent().getParent().get('item');
                const sourceId = this.origin.sourceNode.get('id');
                const targetId = this.origin.targetNode.get('id');
                const addModel = {
                    id: sourceId + '_to_' + targetId,
                    clazz: 'flow',
                    source: sourceId,
                    target: targetId,
                    sourceAnchor: this.origin.sourceAnchor,
                    targetAnchor: this.origin.targetAnchor,
                };
                const resultModel = group.addEdgeModel(subProcess, addModel);
                if (this.graph.executeCommand) {
                    this.graph.executeCommand('update', {
                        itemId: subProcess.get('id'),
                        updateModel: resultModel
                    });
                } else {
                    this.graph.updateItem(node, resultModel);
                }
            }
        },
        addEdge() {
            if (this.origin.targetNode) {
                const timestamp = new Date().getTime();
                let sourceId = this.origin.sourceNode.get('id');
                let targetId = this.origin.targetNode.get('id');
                let sourceType = this.origin.sourceNode.getModel().type;
                let targetType = this.origin.targetNode.getModel().type;

                //检查连线是否合法
                //开始节点，只能连接一个
                if (this.origin.sourceNode.getModel().type == 'start-node') {
                    if (this.origin.targetNode.getModel().type == 'end-node') {
                        this.graph.emit('message', {type: 'warn', msg: '开始节点不能与结束节点直接相连'})
                        return
                    }
                }

                if (this.origin.targetNode.getModel().type == 'start-node') {
                    this.graph.emit('message', {type: 'warn', msg: '开始节点不能作为下游节点'})
                    return
                }
                if (this.origin.sourceNode.getModel().type == 'end-node') {
                    this.graph.emit('message', {type: 'warn', msg: '结束节点不能作为上游节点'})
                    return
                }

                const addModel = {
                    id: 'flow' + timestamp,
                    clazz: 'flow',
                    source: sourceId,
                    target: targetId,
                    sourceAnchor: this.origin.sourceAnchor,
                    targetAnchor: this.origin.targetAnchor,
                };
                let flag = false;
                if (sourceType !== 'path-node' && targetType !== 'path-node') {
                    addModel.edgeType = 'opeEdge';
                    flag = true;
                }
                let index = this.graph.getEdges().findIndex((e) =>
                    e.getModel().source == sourceId && e.getModel().target == targetId
                )
                if (index > -1) {
                    this.graph.emit('message', {type: 'warn', msg: '两节点之间已存在连线'})
                    return
                }
                this.formatEdge(flag, sourceType, targetType);
                if (this.graph.executeCommand) {
                    this.graph.executeCommand('add', {
                        type: 'edge',
                        addModel: addModel
                    });
                } else {
                    this.graph.add('edge', addModel);
                }

            }
        },
        //新建节点手动链接一处的连线之后,自动链接另外一处
        formatEdge(flag, sourceType, targetType) {
            let sourceId = this.origin.sourceNode.get('id');
            let targetId = this.origin.targetNode.get('id');
            let timestamp = '' + new Date().getTime();
            timestamp = timestamp.slice(0, 12);
            let data = this.graph.save();
            let num = -1;
            let mainNode = '';
            if (flag){
                if (this.origin.targetNode && 'kind' in this.origin.targetNode.getModel() && this.origin.targetNode.getModel().kind === 'main') {
                    mainNode = 'target';
                    let edges = this.origin.sourceNode.getEdges();
                    num = edges.filter(e => 'edgeType' in e.getModel() && e.getModel().edgeType === "opeEdge").length;
                }else if (this.origin.sourceNode && 'kind' in this.origin.sourceNode.getModel() && this.origin.sourceNode.getModel().kind === 'main') {
                    mainNode = 'source';
                    let edges = this.origin.targetNode.getEdges();
                    num = edges.filter(e => 'edgeType' in e.getModel() && e.getModel().edgeType === "opeEdge").length;
                }
                if (mainNode === 'target' && num === 0) {//连线的目标站点在工艺路线上
                    let val = this.graph.getEdges().find(e => e.getModel().target === targetId
                        && e.getModel().source !== sourceId
                        && (e.getSource().getModel().type === 'ope-node' || e.getSource().getModel().type === 'start-node'));
                    if (val) {
                        const addModel = {
                            id: 'flow' + timestamp,
                            clazz: 'flow',
                            source: val.getModel().source,
                            target: sourceId,
                            sourceAnchor: val.getModel().sourceAnchor,
                            targetAnchor: (this.origin.sourceAnchor + 3) % 4,
                        };
                        if (flag) {
                            addModel.edgeType = 'opeEdge';
                        }
                        this.graph.removeItem(val);
                        this.graph.add('edge', addModel);
                    }
                } else if (mainNode === 'source' && num === 0) {//连线的起始站点在工艺路线上
                    let val = this.graph.getEdges().find(e => e.getModel().source === sourceId
                        && e.getModel().target !== targetId
                        && (e.getTarget().getModel().type === 'ope-node' || e.getTarget().getModel().type === 'end-node'));
                    if (val) {
                        const addModel = {
                            id: 'flow' + timestamp,
                            clazz: 'flow',
                            source: targetId,
                            target: val.getModel().target,
                            sourceAnchor: (this.origin.targetAnchor + 1) % 4,
                            targetAnchor: val.getModel().targetAnchor,
                        };
                        if (flag) {
                            addModel.edgeType = 'opeEdge';
                        }
                        this.graph.removeItem(val);
                        this.graph.add('edge', addModel);
                    }
                } else {//连线为工艺路线上的站点间连线
                    let sourceEdge = this.graph.getEdges().find(e => e.getModel().source === sourceId
                        && e.getModel().target !== targetId);
                    let targetEdge = this.graph.getEdges().find(e => e.getModel().target === targetId
                        && e.getModel().source !== sourceId);
                    if (sourceEdge && 'edgeType' in sourceEdge.getModel() && sourceEdge.getModel().edgeType === 'opeEdge') {
                        this.graph.removeItem(sourceEdge);
                    }
                    if (targetEdge && 'edgeType' in targetEdge.getModel() && targetEdge.getModel().edgeType === 'opeEdge') {
                        this.graph.removeItem(targetEdge);
                    }
                }
            } else {//非站点间连线
                if (sourceType === 'path-node'){
                    let edge = this.graph.getEdges().find(e => e.getModel().source === sourceId
                        && e.getModel().target !== targetId);
                    if (edge) {
                        this.graph.removeItem(edge);
                    }
                } else if (targetType === 'path-node') {
                    let edge = this.graph.getEdges().find(e => e.getModel().target === targetId
                        && e.getModel().source !== sourceId);
                    if (edge) {
                        this.graph.removeItem(edge);
                    }
                }
            }
        }
    }

    if(payload){
        behavior = {...behavior, ...payload}
    }

    G6.registerBehavior('dragEdge', behavior);
}
